/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 *
 * http://www.gnu.org/copyleft/gpl.html
 */

package l1j.server.server;

import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.server.command.L1Commands;
import l1j.server.server.command.executor.L1CommandExecutor;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.templates.L1Command;

// Referenced classes of package l1j.server.server:
// ClientThread, Shutdown, IpTable, MobTable,
// PolyTable, IdFactory
//

public class GMCommands {
	private static Logger _log = Logger.getLogger(GMCommands.class.getName());

	private static GMCommands _instance;

	private static HashMap<Integer, String> _lastCommands = new HashMap<Integer, String>();

	public static GMCommands getInstance() {
		if (_instance == null) {
			_instance = new GMCommands();
		}
		return _instance;
	}

	private GMCommands() {
	}

	private String complementClassName(final String className) {
		// .が含まれていればフルパスと見なしてそのまま返す
		if (className.contains(".")) {
			return className;
		}

		// デフォルトパッケージ名を補完
		return "l1j.server.server.command.executor." + className;
	}
	private boolean executeDatabaseCommand(final L1PcInstance pc, final String name,final String arg) {
		try {
			final L1Command command = L1Commands.get(name);
			if (command == null) {
				return false;
			}
			if(pc !=null){
			if (pc.getAccessLevel() < command.getLevel()) {
				//pc.sendPackets(new S_ServerMessage(74, "指令 " + name + " ")); // \f1%0は使用できません。

				pc.sendPackets(new S_SystemMessage("GM權限不足無法使用此指令 。"));//opqlo GM指令修正
				return true;
			}
			}

			final Class<?> cls = Class.forName(this.complementClassName(command.getExecutorClassName()));
			final L1CommandExecutor exe = (L1CommandExecutor) cls.getMethod("getInstance").invoke(null);
			exe.execute(pc, name, arg);
			_log.info(pc.getName() + "使用 ." + name + " " + arg + "的指令。");
			return true;

		} catch (final Exception e) {
			_log.log(Level.SEVERE, "error gm command", e);
		}
		return false;
	}


	/**
	 * 系統命令執行
	 * @param pc
	 * @param cmd
	 * @param arg
	 * @return
	 */
	private void executeDatabaseCommand(final String cmd, final String arg) {
		try {
			final L1Command command = L1Commands.get(cmd.toLowerCase());

			if (command == null) {
				_log.log(Level.WARNING,"指令異常: 沒有這個命令(" + cmd.toLowerCase() + ")");
				return;
			}

			if (!command.SystemCanUse()) {
				_log.log(Level.WARNING,"指令異常: 這個命令必須進入遊戲才能執行(" + cmd.toLowerCase() + ")");
				return;
			}

			// 返回与带有给定字符串名的类或接口相关联的 Class 对象。
			final Class<?> cls = Class.forName(this.complementClassName(command.getExecutorClassName()));

			final L1CommandExecutor exe = (L1CommandExecutor) cls.getMethod("getInstance").invoke(null);
			exe.execute(null, cmd.toLowerCase(), arg.toLowerCase());

			//_log.warn("系統命令執行: " + cmd + " " + arg);


		} catch (final Exception e) {
			_log.log(Level.WARNING,"管理者指令異常!", e);
		}
	}



	public void handleCommands(final L1PcInstance gm, final String cmdLine) {
		final StringTokenizer token = new StringTokenizer(cmdLine);
		// 最初の空白までがコマンド、それ以降は空白を区切りとしたパラメータとして扱う
		final String cmd = token.nextToken();
		String param = "";
		while (token.hasMoreTokens()) {
			param = new StringBuilder(param).append(token.nextToken()).append(' ').toString();
		}
		param = param.trim();

		// データベース化されたコマンド
		if (this.executeDatabaseCommand(gm, cmd, param)) {
			if (!cmd.equalsIgnoreCase("r")) {
				_lastCommands.put(gm.getId(), cmdLine);
			}
			return;
		}
		if (cmd.equalsIgnoreCase("r")) {
			if (!_lastCommands.containsKey(gm.getId())) {
				gm.sendPackets(new S_ServerMessage(74, "指令 " + cmd + " ")); // \f1%0は使用できません。
				return;
			}
			this.redo(gm, param);
			return;
		}
		gm.sendPackets(new S_SystemMessage("指令  " + cmd + " 不存在。"));
	}

	/**
	 * 系統命令執行
	 * @param cmdLine
	 */
	public void handleCommands(final String cmdLine) {
		final StringTokenizer token = new StringTokenizer(cmdLine);

		String cmd;
		try {
			// 取回命令前段
			cmd = token.nextToken();

		} catch (final Exception e) {
			_log.log(Level.WARNING,"系統命令空白!");
			return;
		}

		String param = "";
		while (token.hasMoreTokens()) {
			param = new StringBuilder(param).append(token.nextToken()).append(' ').toString();
		}

		// 返回字符串的副本，忽略前导空白和尾部空白。(命令中段)
		param = param.trim();

		this.executeDatabaseCommand(cmd, param);
	}

	private void redo(final L1PcInstance pc, final String arg) {
		try {
			final String lastCmd = _lastCommands.get(pc.getId());
			if (arg.isEmpty()) {
				pc.sendPackets(new S_SystemMessage("指令 " + lastCmd + " 重新執行。"));
				this.handleCommands(pc, lastCmd);
			} else {
				// 引数を変えて実行
				final StringTokenizer token = new StringTokenizer(lastCmd);
				final String cmd = token.nextToken() + " " + arg;
				pc.sendPackets(new S_SystemMessage("指令  " + cmd + " 執行。"));
				this.handleCommands(pc, cmd);
			}
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
			pc.sendPackets(new S_SystemMessage(".r 指令錯誤。"));
		}
	}
}
